package com.tcm.doctor.service;

import cn.hutool.core.util.ObjectUtil;
import com.base.core.exception.ServiceException;
import com.base.core.pager.PageBean;
import com.base.core.pager.PageContext;
import com.base.core.utils.JwtUtils;
import com.base.core.utils.ListJoinUtils;
import com.base.core.utils.ListUtils;
import com.base.core.utils.R;
import com.base.genid.generator.UidGenerator;
import com.base.core.dozer.DozerConvert;
import com.tcm.doctor.domain.dto.DoctorDTO;
import com.tcm.doctor.domain.dto.DoctorServicesDTO;
import com.tcm.doctor.domain.dto.RecommendDoctorDTO;
import com.tcm.doctor.domain.dto.UserDoctorDTO;
import com.tcm.doctor.domain.entity.Doctor;
import com.tcm.doctor.domain.entity.DoctorJobtitle;
import com.tcm.doctor.domain.entity.DoctorServices;
import com.tcm.doctor.domain.entity.DoctorVerify;
import com.tcm.doctor.domain.enums.BusinessCodeEnum;
import com.tcm.doctor.mapper.DoctorJobtitleMapper;
import com.tcm.doctor.mapper.DoctorMapper;
import com.tcm.doctor.mapper.DoctorServicesMapper;
import com.tcm.doctor.mapper.DoctorVerifyMapper;
import io.jsonwebtoken.Claims;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@DubboService(version = "0.0.1-alpha", retries = 3, timeout = 6000, delay = -1)
public class DoctorServiceImpl implements DoctorService {

    @Autowired
    private DoctorMapper doctorMapper;

    @DubboReference(version = "0.0.1-beta",group = "cached-uid",timeout = 6000, check = false,retries = 3)
    private UidGenerator uidGenerator;

    @Autowired
    private DoctorJobtitleMapper doctorJobtitleMapper;

    @DubboReference(version = "0.0.1-alpha",timeout = 6000, check = false,retries = 3)
    private DoctorServicesService doctorServicesService;

    @Autowired
    private DoctorVerifyMapper doctorVerifyMapper;


    /**
     * 获得医生与服务信息
     *
     * @param userId
     * @return Doctor
     */
    @Override
    public DoctorDTO findDoctorByUserId(Long userId) throws ServiceException {
        Doctor doctor = doctorMapper.findByUserId(userId);
        DoctorDTO doctorDTO = new DoctorDTO();
        if(ObjectUtil.isEmpty(doctor)){
            return null;
        }
        BeanUtils.copyProperties(doctor, doctorDTO);
        return doctorDTO;
    }

    /**
     * 获得医生列表
     *
     * @param userIds
     * @return Doctor
     */
    @Override
    public List<DoctorDTO> listDoctorByUserIds(List<Long> userIds) throws ServiceException {
        List<Doctor> doctors = doctorMapper.listDoctorByUserIds(userIds);
        if(doctors.isEmpty() || doctors == null){
            return null;
        }
        List<DoctorDTO> doctorDTOS = doctors.stream().map(doctor -> {
            DoctorDTO doctorDTO = new DoctorDTO();
            BeanUtils.copyProperties(doctor, doctorDTO);
            return doctorDTO;
        }).collect(Collectors.toList());
        return doctorDTOS;
    }

    /**
     * 获得医生与认证信息
     *
     * @param userId
     * @return Doctor
     */
    @Override
    public DoctorDTO findDoctorVerifyByUserId(Long userId) throws ServiceException {
        Doctor doctor = doctorMapper.findByUserId(userId);
        DoctorVerify doctorVerify = doctorVerifyMapper.findByUserId(userId);
        DoctorDTO doctorDTO = new DoctorDTO();
        BeanUtils.copyProperties(doctor, doctorDTO);
        doctorDTO.setDoctorVerify(doctorVerify);
        return doctorDTO;
    }

    /**
     * 获取单条数数据
     *
     * @param token
     * @return
     */
    @Override
    public DoctorDTO findDoctorByToken(String token) throws ServiceException{
        DoctorDTO userDto = null;
        try {
            JwtUtils jwtUtils = new JwtUtils();
            Claims claims = jwtUtils.decode(token);
            if(ObjectUtil.isEmpty(claims)){
                R.throwFail(BusinessCodeEnum.TOKEN_FAIL_PARSE);
            }
            Long userId = (Long) claims.get("userId");
            Doctor user = doctorMapper.findByUserId(userId);
            if (ObjectUtil.isNotEmpty(user)) {
                userDto = DozerConvert.copyProperties(user, DoctorDTO.class);
            }else {
                userDto = new DoctorDTO();
                userDto.setUserId(userId);
            }
        } catch (ServiceException e) {
            e.printStackTrace();
            R.throwFail(BusinessCodeEnum.FAILED_TO_QUERY_DOCTOR);
        }
        return userDto;
    }

    /**
     * 新增医生信息
     *
     * @param doctorDTO
     */
    @Override
    public void saveDoctor(DoctorDTO doctorDTO) throws Exception {
        if(ObjectUtil.isEmpty(doctorDTO.getUserId())){
            R.throwFail(BusinessCodeEnum.DOCTOR_USER_ID_NOT_EXISTS);
        }
        if(doctorDTO.getUserId().equals(0L)){
            R.throwFail(BusinessCodeEnum.DOCTOR_USER_ID_NOT_EXISTS);
        }
        Doctor doctor = DozerConvert.copyProperties(doctorDTO, Doctor.class);

        if(ObjectUtil.isNotEmpty(doctor.getJobtitleId())){
            DoctorJobtitle doctorJobtitle = doctorJobtitleMapper.findById(doctor.getJobtitleId());
            doctor.setJobtitleLevel(doctorJobtitle.getLevel());
        }
        doctor.setUpdateTime(LocalDateTime.now());
        doctor.setDeleted(new Byte("0"));
        Doctor doc = doctorMapper.findByUserId(doctor.getUserId());
        if(ObjectUtil.isEmpty(doc)){
            doctor.setId(uidGenerator.getUID());
            doctor.setCreateTime(LocalDateTime.now());
            doctor.setUpdateTime(LocalDateTime.now());
            doctorMapper.insert(doctor);
        }else {
            doctor.setUserId(doc.getUserId());
            doctor.setUpdateTime(LocalDateTime.now());
            doctorMapper.update(doctor);
        }

    }


    /**
     * 永久删除
     *
     * @param userId
     */
    @Override
    public void deleteDoctor(Long userId) throws ServiceException{
        doctorMapper.deleteByUserId(userId);
    }

    /**
     * 删除到回收站
     *
     * @param userId
     */
    @Override
    public void deleteLogicDoctor(Long userId) throws ServiceException{
        doctorMapper.deleteLogicByUserId(userId);
    }


    /**
     * 分页查询医生列表
     * @param start
     * @param pagesize
     * @return
     */
    @Override
    public PageBean<UserDoctorDTO> listDoctorPage(Long start, Long pagesize) throws ServiceException{
        int total = doctorMapper.countDoctor();
        PageContext.setPageSize(pagesize);
        PageContext.setCurrentPage(start);
        PageContext.setDataCount(new Long(total));
        if(total == 0){
            return new PageBean<>(null);
        }
        List<Doctor> doctorList = doctorMapper.listDoctorPage(PageContext.getStart(),pagesize);
        List<Long> userIds =  ListUtils.extractToList(doctorList, "userId");
        List<DoctorServicesDTO> doctorServicesList;
        doctorServicesList = doctorServicesService.listBacthServices(
               userIds, "consultation");
        if(doctorServicesList == null){
            //从表为空直接返回主表数据
            List<UserDoctorDTO> doctorDTOS = DozerConvert.copyList(doctorList, UserDoctorDTO.class);
            return new PageBean<>(doctorDTOS);
        }
        //从表转换为map
        Map<Long, List<DoctorServicesDTO>> doctorMaps = doctorServicesList.stream().collect(
           Collectors.groupingBy(DoctorServicesDTO::getDoctorId)
        );
        //遍历第一个主表数据
        List<UserDoctorDTO> userDoctorDTOS = doctorList.stream().map(doctor -> {
            UserDoctorDTO userDoctorDTO = new UserDoctorDTO();
            BeanUtils.copyProperties(doctor, userDoctorDTO);
            if(doctorMaps.containsKey(doctor.getUserId())){
                userDoctorDTO.setDoctorServicesDTOList(doctorMaps.get(doctor.getUserId()));
            }
            return userDoctorDTO;
        }).collect(Collectors.toList());

        PageBean<UserDoctorDTO> doctorDTOPageBean = new PageBean<>(userDoctorDTOS);
        PageContext.clear();
        return doctorDTOPageBean;
    }

    /**
     * 查询推荐医生列表
     * @param hospitalId
     * @param quantity
     * @return
     */
    @Override
    public List<RecommendDoctorDTO> listRecommendDoctor(Long hospitalId, Integer quantity) throws ServiceException{

        List<Doctor> doctorList = doctorMapper.listRecommendDoctor(hospitalId, quantity);
        if(doctorList == null || doctorList.isEmpty()){
            return null;
        }
        List<Long> userIds =  ListUtils.extractToList(doctorList, "userId");
        List<DoctorServicesDTO> doctorServicesList = doctorServicesService.listBacthServices(userIds, "consultation");
        Double minPrice =doctorServicesList.stream().mapToDouble(DoctorServicesDTO->DoctorServicesDTO
                .getValues().getPrice().doubleValue()).min().getAsDouble();
        List<RecommendDoctorDTO> recommendDoctorDTOS = doctorList.stream().map(doctor -> {
            RecommendDoctorDTO recommendDoctorDTO = new RecommendDoctorDTO();
            BeanUtils.copyProperties(doctor, recommendDoctorDTO);
            recommendDoctorDTO.setMinServicePrice(new BigDecimal(minPrice));
            return recommendDoctorDTO;
        }).collect(Collectors.toList());
        return recommendDoctorDTOS;
    }
}

